/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __MATH_JOINTMATRIX_H__
#define __MATH_JOINTMATRIX_H__


extern odJointMat	jointMat_identity;

class odJointMat {
public:
	odMat3			rotation;
	odVec3			translation;

					odJointMat (void);
	explicit		odJointMat (const odQuat &orientation, const odVec3 &translation);
	explicit		odJointMat (const odMat3 &rotation, const odVec3 &translation);

	odJointMat &	operator = (const odJointMat &jointMat);
	bool			operator == (const odJointMat &jointMat) const;
	bool			operator != (const odJointMat &jointMat) const;

	odJointMat		operator - () const;

	odJointMat		operator + (const odJointMat &jointMat) const;
	odJointMat		operator * (const odJointMat &jointMat) const;
	odJointMat		operator * (float scale) const;
	odJointMat &	operator += (const odJointMat &jointMat);
	odJointMat &	operator *= (const odJointMat &jointMat);
	odJointMat &	operator *= (float scale);

	void			Set (const odQuat &orientation, const odVec3 &translation);
	void			Set (const odMat3 &rotation, const odVec3 &translation);
	void			Identity (void);
	bool			IsIdentity (void) const;
	void			TransformVector (const odVec3 &in, odVec3 &out) const;
	void			TransformNormal (const odVec3 &in, odVec3 &out) const;

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);

	odMat3			ToMat3 (void) const;
	odVec3			ToVec3 (void) const;

	const char *	ToString (int precision = 2) const;
};

INLINE odJointMat::odJointMat (void){

}

INLINE odJointMat::odJointMat (const odQuat &orientation, const odVec3 &translation){

	this->rotation = orientation.ToMat3();
	this->translation = translation;
}

INLINE odJointMat::odJointMat (const odMat3 &rotation, const odVec3 &translation){

	this->rotation = rotation;
	this->translation = translation;
}

INLINE odJointMat &odJointMat::operator = (const odJointMat &jointMat){

	rotation = jointMat.rotation;
	translation = jointMat.translation;

	return *this;
}

INLINE bool odJointMat::operator == (const odJointMat &jointMat) const {

	if (rotation != jointMat.rotation || translation != jointMat.translation)
		return false;

	return true;
}

INLINE bool odJointMat::operator != (const odJointMat &jointMat) const {

	if (rotation == jointMat.rotation && translation == jointMat.translation)
		return false;

	return true;
}

INLINE odJointMat odJointMat::operator - () const {

	odJointMat	result;

	result.rotation = rotation.Transpose();

	rotation.UnprojectVector(translation, result.translation);
	result.translation = -result.translation;

	return result;
}

INLINE odJointMat odJointMat::operator + (const odJointMat &jointMat) const {

	odJointMat	result;

	result.rotation[0] = rotation[0] + jointMat.rotation[0];
	result.rotation[1] = rotation[1] + jointMat.rotation[1];
	result.rotation[2] = rotation[2] + jointMat.rotation[2];
	result.translation = translation + jointMat.translation;

	return result;
}

INLINE odJointMat odJointMat::operator * (const odJointMat &jointMat) const {

	odJointMat	result;

	result.rotation = rotation * jointMat.rotation;

	rotation.ProjectVector(jointMat.translation, result.translation);
	result.translation += translation;

	return result;
}

INLINE odJointMat odJointMat::operator * (float scale) const {

	odJointMat	result;

	result.rotation[0] = rotation[0] * scale;
	result.rotation[1] = rotation[1] * scale;
	result.rotation[2] = rotation[2] * scale;
	result.translation = translation * scale;

	return result;
}

INLINE odJointMat &odJointMat::operator += (const odJointMat &jointMat){

	rotation[0] += jointMat.rotation[0];
	rotation[1] += jointMat.rotation[1];
	rotation[2] += jointMat.rotation[2];
	translation += jointMat.translation;

	return *this;
}

INLINE odJointMat &odJointMat::operator *= (const odJointMat &jointMat){

	odVec3	tmp;

	rotation *= jointMat.rotation;

	jointMat.rotation.ProjectVector(translation, tmp);
	translation = tmp + jointMat.translation;

	return *this;
}

INLINE odJointMat &odJointMat::operator *= (float scale){

	rotation[0] *= scale;
	rotation[1] *= scale;
	rotation[2] *= scale;
	translation *= scale;

	return *this;
}

INLINE void odJointMat::Set (const odQuat &orientation, const odVec3 &translation){

	this->rotation = orientation.ToMat3();
	this->translation = translation;
}

INLINE void odJointMat::Set (const odMat3 &rotation, const odVec3 &translation){

	this->rotation = rotation;
	this->translation = translation;
}

INLINE void odJointMat::Identity (void){

	rotation.Identity();
	translation.Clear();
}

INLINE bool odJointMat::IsIdentity (void) const {

	if (!rotation.IsIdentity() || !translation.IsCleared())
		return false;

	return true;
}

INLINE void odJointMat::TransformVector (const odVec3 &in, odVec3 &out) const {

	rotation.ProjectVector(in, out);
	out += translation;
}

INLINE void odJointMat::TransformNormal (const odVec3 &in, odVec3 &out) const {

	rotation.ProjectVector(in, out);
	out.NormalizeFast();
}

INLINE const float *odJointMat::ToFloatPtr (void) const {

	return &rotation[0].x;
}

INLINE float *odJointMat::ToFloatPtr (void){

	return &rotation[0].x;
}


#endif	// __MATH_JOINTMATRIX_H__
